package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.util.StringUtil;
import com.google.common.collect.Lists;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 使用缓存优化深度计算，避免重复查询数据库
     */
    private final Map<String, Integer> depthCache = new ConcurrentHashMap<>();

    @Cacheable(value = CacheConstant.RESOURCE_PREFIX, key = "#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> findResourceList(ResourceDto resourceDto) {
        Resource resource = new Resource();
        BeanUtil.copyProperties(resourceDto, resource);
        List<Resource> resourceList = resourceMapper.selectList(resource);
        return BeanUtil.copyToList(resourceList, ResourceVo.class);
    }

    @Cacheable(value = CacheConstant.RESOURCE_TREE)
    @Override
    public TreeVo resourceTreeVo(ResourceDto resourceDto) {
        List<Resource> resourceList = getResources();

        // 将资源数据 List<Resource> resourceList 放入 TreeVo
        // 数据库没有根节点，此处构建根节点
        Resource rootResource = new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        rootResource.setResourceName("智慧养老院");
        System.out.println("resourceTreeVo()_rootResource:" + rootResource);

        // 要返回的树形集合
        // TreeItemVo = id + label + children
        List<TreeItemVo> itemVos = new ArrayList<>();

        // 递归构建树形结构
        recursionTreeItem(itemVos, rootResource, resourceList);

        return TreeVo.builder().items(itemVos).build();
    }

    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    @Transactional(rollbackFor = BaseException.class)
    @Override
    public void createResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        // 查询父资源
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        resource.setDataState(parentResource.getDataState());
        boolean isIgnore = true;
        // 判断是否是按钮，如果是，则不限制层级；否则，菜单限制不超过三级
        if (StringUtil.isNotEmpty(resourceDto.getResourceType())
                && resourceDto.getResourceType().equals(SuperConstant.BUTTON)) {
            isIgnore = false;
        }
        // 创建当前资源的编号
        String resourceNo = createResourceNo(resourceDto.getParentResourceNo(), isIgnore);
        resource.setResourceNo(resourceNo);
        System.out.println("createResource()_resourceNo:" + resourceNo);
        resourceMapper.insert(resource);
    }

    @Caching(evict = {
            @CacheEvict(value = CacheConstant.RESOURCE_LIST, allEntries = true),
            @CacheEvict(value = CacheConstant.RESOURCE_TREE, allEntries = true)
    })
    @Transactional(rollbackFor = BaseException.class)
    @Override
    public void updateResource(ResourceDto resourceDto) {
        // resource 从前端传来的，将要更新入数据库的资源
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        Map<Long, Long> map = new HashMap<>();
        // 1. 获取当前资源的所有子孙节点
        List<Resource> allDescendants = getAllDescendants(resource);
        // 2. 筛选出所有按钮类型的资源
        List<Resource> buttons = allDescendants.stream()
                .filter(res -> SuperConstant.BUTTON.equals(res.getResourceType()))
                .collect(Collectors.toList());
        // 3. 为每个按钮资源建立映射
        for (Resource button : buttons) {
            // 获取按钮的直接父资源
            Resource parent = resourceMapper.selectByResourceNo(button.getParentResourceNo());

            if (parent != null) {
                // 存储按钮ID → 父资源ID
                map.put(button.getId(), parent.getId());
            } else {
                System.err.println("警告: 按钮 " + button.getResourceNo() + " 的父资源不存在");
            }
        }

        // parentResource是更新后，新的父资源。resource以及自身下的所有资源需要跟随新的父资源
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        // 记录父资源的 data_state   变更到父资源下的所有子资源与父资源的状态保持一致
        String parentState = parentResource.getDataState();
        System.out.println("updateResource()_resource:" + resource);
        System.out.printf("updateResource()_resource_id:" + resource.getId());
        // 获取旧的resource  对于任意资源，不管其父资源或者resourceNo如何变化，其id始终不变
        Resource resourceOld = resourceMapper.selectById(resource.getId());
        resource.setDataState(parentResource.getDataState());
        resource.setCreateTime(resourceOld.getCreateTime());
        resource.setUpdateTime(LocalDateTime.now());
        resource.setCreateBy(resourceOld.getCreateBy());
        resource.setUpdateBy(resourceOld.getCreateBy());

        // 3. 判断是否为按钮资源（按钮不限制层级）
        boolean isMenuResource = !SuperConstant.BUTTON.equals(resourceDto.getResourceType());

        // 4. 检查父资源是否变更
        boolean isParentChanged = !Objects.equals(resourceOld.getParentResourceNo(), parentResource.getResourceNo());
        if (!isParentChanged) {
            // 父资源未变：直接更新
            resourceMapper.updateByPrimaryKey(resource);
            return;
        }

        // 5. 父资源变更：检查合法性
        if (resourceOld.getResourceNo().equals(parentResource.getResourceNo()) ||
                isChildResource(parentResource, resourceOld)) {
            throw new RuntimeException("编辑失败，无法将自身或其子资源作为上级菜单");
        }

        // 6. 检查层级深度（仅菜单资源）
        if (isMenuResource) {
            int newParentDepth = getParentDepth(parentResource.getResourceNo());
            int currentDepth = getChildDepth(resourceOld.getResourceNo());
            System.out.println("newParentDepth:" + newParentDepth + "    currentDepth:" + currentDepth);
            if ((newParentDepth + currentDepth) > 3) {
                throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
            }
        }

        // 7. 更新当前资源的编号 -- 由于已经进行了深度校验，后面不再需要校验
        String newResourceNo = createResourceNo(parentResource.getResourceNo(), false);
        resource.setResourceNo(newResourceNo);

        // 8. 递归更新所有menu子资源（使用新编号作为基准）
        updateMenuChildrenResourceNo(resourceOld, newResourceNo, parentState);

        // TODO 第8步的递归操作会修改菜单资源的 resource_no
        //  第9步需要基于更新后的菜单资源来更新按钮
        //  但第9步可能在递归完成前就开始执行
        //  此处需要事务处理

        // 9. 根据map，将button与其父节点menu一一对应
        updateButtonResourceNo(map);
        // 10. 更新当前资源
        resourceMapper.updateByPrimaryKey(resource);

    }

    @Transactional
    @Override
    public void enableResource(ResourceDto resourceDto) {
        // 1. 获取当前资源
        Resource resource = resourceMapper.selectByResourceNo(resourceDto.getResourceNo());
        if (resource == null) {
            throw new RuntimeException("该资源不存在");
        }

        // 如果父资源为禁用状态，则无法启用子资源
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        if ((parentResource.getDataState().equals("1")) && (resource.getDataState().equals("1"))) {
            throw new RuntimeException("启用失败");
        }

        // 2. 获取资源自身及所有子节点的ID列表
        List<String> allResourceNos = new ArrayList<>();
        allResourceNos.add(resource.getResourceNo()); // 添加自身ID

        // 递归获取所有子节点ID
        collectChildrenIds(resource.getResourceNo(), allResourceNos);

        // 3. 批量更新状态
        if (!allResourceNos.isEmpty()) {
            resourceMapper.batchUpdateEnable(allResourceNos);
        }
    }

    /**
     * 根据用户id查询对应的资源数据
     *
     * @param userId
     * @return
     */
    @Override
    public List<MenuVo> menus(Long userId) {
        //查询用户对应的所有的菜单数据
        List<MenuVo> menuVoList = resourceMapper.findListByUserId(userId);
        if (CollUtil.isEmpty(menuVoList)) {
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }
        //数据进行分组（parentNo:[{},{}]）
        //key: 父资源编号
        //value: 直接子资源
        Map<String, List<MenuVo>> parentRNoMap = menuVoList
                .stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        //遍历所有数据
        menuVoList.forEach(menuVo -> {
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
            menuVo.setRedirect("/" + menuVo.getName());
            //根据父编号到map中查找是否包含子菜单，如果包含则设置为当前菜单的子菜单
            List<MenuVo> menuVos = parentRNoMap.get(menuVo.getResourceNo());
            if (!EmptyUtil.isNullOrEmpty(menuVos)) {
                menuVos.forEach(m -> {
                    m.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
                    m.setRedirect(m.getName());
                });
                menuVo.setChildren(menuVos);
            }
        });
        //根据根编号查找所有的子
        return parentRNoMap.get(SuperConstant.ROOT_PARENT_ID);
    }

    @Override
    public List<MenuVo> buttons() {
        //全部的菜单，包含了菜单和按钮
        Resource resource = Resource.builder()
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID)).build();
        List<Resource> resources = resourceMapper.selectList(resource);
        List<MenuVo> list = new ArrayList<>();
        recursionButtonVo(list, resources);
        return list;
    }

    @Transactional(rollbackFor = BaseException.class)
    @Override
    public int deleteMenuById(String menuId) {
        if (hasChildByMenuId(menuId)) {
            throw new RuntimeException("存在子菜单,不允许删除");
        }
        return resourceMapper.deleteMenuById(menuId);
    }

    /**
     * 创建资源的编号
     *
     * @param parentResourceNo
     * @param isIgnore
     * @return
     */
    private String createResourceNo(String parentResourceNo, boolean isIgnore) {
        /*
          100 001 000 000 000
          a   b   c   d   e
          a + b: 根层级：智慧养老院 100 001 000 000 000
          c: 第一层级 100 001 001 000 000
          d: 第二层级 100 001 001 001 000
          e: 第三层级 100 001 001 001 001 无法再加入新的层级
         */
        // 菜单资源的编号限制不超过三级
        System.out.println("createResourceNo_parentResourceNo" + parentResourceNo);
        if (isIgnore && getParentDepth(parentResourceNo) > 2) {
            System.out.println("getParentDepth:" + getParentDepth(parentResourceNo));
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        // 根据父资源编号查询子资源
        Resource query = Resource.builder().parentResourceNo(parentResourceNo).build();
        return createChildNo(parentResourceNo, query);
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean hasChildByMenuId(String menuId) {
        int result = resourceMapper.hasChildByMenuId(menuId);
        return result > 0 ? true : false;
    }

    /**
     * 递归按钮
     *
     * @param list
     * @param resources
     * @return
     */
    public List<MenuVo> recursionButtonVo(List<MenuVo> list, List<Resource> resources) {
        for (Resource resource : resources) {
            if (resource.getParentResourceNo().equals(SuperConstant.ROOT_PARENT_ID)) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resource.getRequestPath());
                menuVo.setName(resource.getResourceName());
                menuVo.setChildren(getAllChildrens(resource, resources));
                list.add(menuVo);
            }
        }
        return list;
    }

    /**
     * 递归获取菜单和按钮
     *
     * @param resource
     * @param resources
     * @return
     */
    private List<MenuVo> getAllChildrens(Resource resource, List<Resource> resources) {

        List<MenuVo> childrenList = Lists.newArrayList();
        for (Resource resourceVo : resources) {
            if (resourceVo.getParentResourceNo().equals(resource.getResourceNo())) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resourceVo.getRequestPath());
                menuVo.setName(resourceVo.getResourceName());
                menuVo.setChildren(getAllChildrens(resourceVo, resources));
                childrenList.add(menuVo);
            }
        }

        return childrenList;
    }

    /**
     * 递归菜单
     *
     * @param list
     * @param resources 根节点的所有直接子节点
     * @return
     */
    public List<MenuVo> recursionMenuVo(List<MenuVo> list, List<Resource> resources) {
        for (Resource resource : resources) {
            // 将 根节点SuperConstant.ROOT_PARENT_ID 的每一个直接子节点封装成一个menuVo，它的所有子节点成为一个列表 List<MenuVo> list
            if (resource.getParentResourceNo().equals(SuperConstant.ROOT_PARENT_ID)) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resource.getRequestPath());
                menuVo.setName(resource.getResourceName());
                menuVo.setPath("/" + resource.getRequestPath());
//                menuVo.setComponent(SuperConstant.COMPONENT_LAYOUT);

                MenuMetaVo menuMetaVo = MenuMetaVo.builder()
                        .icon(resource.getIcon())
                        .title(resource.getResourceName())
                        .build();
                menuVo.setMeta(menuMetaVo);
                menuVo.setRedirect("/" + resource.getResourceName());

                menuVo.setChildren(getChildrens(resource, resources, resource.getRequestPath()));
                list.add(menuVo);
            }
        }
        return list;
    }

    /**
     * 递归获取菜单和按钮
     * 以递归的方式，将一个扁平的资源列表（resources）转换成一个树形结构的前端菜单列表（List<MenuVo>）。
     * 它从一个给定的父节点（resource）开始，查找其所有子节点，并为每个子节点创建对应的菜单对象，然后递归地处理这些子节点的子节点。
     *
     * @param resource                                 当前要处理的父级资源节点。方法会寻找这个节点的所有子节点。
     * @param resources                                包含所有资源的扁平列表。从这个列表中查找当前父节点的子节点
     * @param component：当前父节点对应的前端组件路径前缀。用于拼接出子组件完整的路径
     * @return 返回当前父节点 resource 下的所有子菜单集合
     */
    private List<MenuVo> getChildrens(Resource resource, List<Resource> resources, String component) {

        List<MenuVo> childrenList = Lists.newArrayList();
        for (Resource resourceVo : resources) {
            if (resourceVo.getParentResourceNo().equals(resource.getResourceNo())) {
                MenuVo menuVo = new MenuVo();
                menuVo.setPath(resourceVo.getRequestPath());
                menuVo.setName(resourceVo.getResourceName());
                // menuVo.setPath(resource.getRequestPath());
//                menuVo.setComponent(component + "/" + resourceVo.getRequestPath());

                MenuMetaVo menuMetaVo = MenuMetaVo.builder()
                        .icon(resourceVo.getIcon())
                        .title(resourceVo.getResourceName())
                        .build();
                menuVo.setMeta(menuMetaVo);

                menuVo.setRedirect("/" + resource.getResourceName() + "/" + resourceVo.getResourceName());

                menuVo.setChildren(getChildrens(resourceVo, resources, resource.getRequestPath()));
                childrenList.add(menuVo);
            }
        }
        return childrenList;
    }


    /**
     * 递归收集所有子节点ID
     *
     * @param parentResourceNo
     * @param allResourceNos
     */
    private void collectChildrenIds(String parentResourceNo, List<String> allResourceNos) {
        // 查询直接子节点
        Resource query = Resource.builder().parentResourceNo(parentResourceNo).build();
        List<Resource> children = resourceMapper.selectList(query);

        for (Resource child : children) {
            allResourceNos.add(child.getResourceNo());
            // 递归收集孙节点
            collectChildrenIds(child.getResourceNo(), allResourceNos);
        }
    }


    /**
     * 递归更新子资源编号
     *
     * @param currentResource
     * @param newParentNo
     * @param dataState
     */
    private void updateMenuChildrenResourceNo(Resource currentResource,
                                              String newParentNo,
                                              String dataState) {
        // 获取当前资源的所有直接子资源
        Resource query = Resource.builder()
                .parentResourceNo(currentResource.getResourceNo())
                .resourceType(SuperConstant.MENU)
                .build();
        List<Resource> children = resourceMapper.selectList(query);

        for (Resource child : children) {
            // 菜单类型：使用原有逻辑生成编号
            String newChildNo = updateMenuResourceNo(newParentNo);
            // 更新子资源信息
            updateChildResource(child, newParentNo, newChildNo, dataState);
            // 递归更新孙资源（按钮类型没有子节点）
            updateMenuChildrenResourceNo(child, newChildNo, dataState);
        }
    }

    private String updateMenuResourceNo(String parentResourceNo) {
        // 判断父节点深度，若大于2则抛出异常
        if (getParentDepth(parentResourceNo) > 2) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        // 查询父节点下的菜单资源和按钮资源
        Resource query = Resource.builder()
                .parentResourceNo(parentResourceNo)
                .build();
        return createChildNo(parentResourceNo, query);
    }

    private void updateButtonResourceNo(Map<Long, Long> map) {
        for (Map.Entry<Long, Long> entry : map.entrySet()) {
            final Long childResourceId = entry.getKey();
            final Long parentResourceId = entry.getValue();

            // 关键：在循环内创建新引用
            final Resource currentChild = resourceMapper.selectById(childResourceId);
            final Resource currentParent = resourceMapper.selectById(parentResourceId);

            // 调试日志（使用final变量）
            System.out.println("更新按钮: ID=" + childResourceId +
                    " | 当前父编号: " + currentChild.getParentResourceNo() +
                    " | 正确父编号: " + currentParent.getResourceNo());

            // 验证父资源类型
            if (!SuperConstant.MENU.equals(currentParent.getResourceType())) {
                System.err.println("错误: 父资源非菜单类型");
                continue;
            }

            // 检查是否需要更新
            if (!currentChild.getParentResourceNo().equals(currentParent.getResourceNo())) {
                // 创建新对象避免引用污染
                Resource updateChild = new Resource();
                updateChild.setId(currentChild.getId());
                updateChild.setParentResourceNo(currentParent.getResourceNo());
                updateChild.setUpdateTime(LocalDateTime.now());

                // 仅更新必要字段
                int rows = resourceMapper.updateParentResourceNo(
                        updateChild.getId(),
                        updateChild.getParentResourceNo(),
                        updateChild.getUpdateTime()
                );

                System.out.println("更新结果: " + (rows > 0 ? "成功" : "失败"));
            }
        }
    }


    private String createChildNo(String parentResourceNo, Resource query) {
        List<Resource> resources = resourceMapper.selectList(query);
        if (EmptyUtil.isNullOrEmpty(resources)) {
            // 父资源无子节点，创建新的节点编号
            // 100 001 001 001 000 -> 100 001 001 001 001
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            // 父资源有子节点，在已有的节点上追加编号
            // 100 001 001 001 000 -> 100 001 001 001 001 -> 100 001 001 001 002
            // 获取已有子节点的最大值
            Long maxNo = resources.stream()
                    .map(resource -> Long.valueOf(resource.getResourceNo())).max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(maxNo), true);
        }
    }


    private void updateChildResource(Resource child, String newParentNo, String newChildNo, String dataState) {
        System.out.println("newParentNo: " + newParentNo + " newChildNo: " + newChildNo);
        // 更新子资源信息
        child.setParentResourceNo(newParentNo);
        child.setResourceNo(newChildNo);
        child.setUpdateTime(LocalDateTime.now());
        child.setDataState(dataState);
        resourceMapper.updateByPrimaryKey(child);
    }


    /**
     * 计算资源深度
     * 父资源的深度应该从根节点算起
     *
     * @param resourceNo
     * @return
     */
    private int getParentDepth(String resourceNo) {
        // 处理后的编号长度除以3得到深度
        return NoProcessing.processString(resourceNo).length() / 3 - 2;
    }

    /**
     * 子节点的深度是从自身出发，其所有子节点的最大深度
     *
     * @param resourceNo
     * @return
     */
    private int getChildDepth(String resourceNo) {

        // 1. 查询当前资源节点
        Resource currentResource = resourceMapper.selectByResourceNo(resourceNo);
        if (currentResource == null) {
            return 0; // 资源不存在，深度为0
        }

        // 2. 获取直接子节点
        Resource query = Resource.builder()
                .parentResourceNo(resourceNo)
                .resourceType(SuperConstant.MENU)
                .build();
        List<Resource> children = resourceMapper.selectList(query);

        // 3. 如果没有子节点，则深度为1（只有当前节点自身）
        if (children.isEmpty()) {
            return 1;
        }

        // 4. 递归计算所有子节点的深度
        int maxChildDepth = 0;
        for (Resource child : children) {
            int childDepth = getChildDepth(child.getResourceNo());
            maxChildDepth = Math.max(maxChildDepth, childDepth);
        }

        // 5. 当前节点深度 = 最大子节点深度 + 1
        return maxChildDepth + 1;
    }

    /**
     * 判断资源A是否是资源B的子资源
     * 递归判断是否存在父子关系
     */
    private boolean isChildResource(Resource resourceA, Resource resourceB) {
        // 如果资源A是资源B的子资源，返回true
        if (resourceA.getParentResourceNo().equals(resourceB.getResourceNo())) {
            return true;
        }

        // 如果资源A不是直接子资源，则递归检查其父资源是否是资源B
        Resource parentResource = resourceMapper.selectByResourceNo(resourceA.getParentResourceNo()); // 通过资源编号获取资源
        if (parentResource == null) {
            return false; // 如果资源不存在，返回false
        }

        return isChildResource(parentResource, resourceB);
    }

    /**
     * 递归构建树形结构
     *
     * @param itemVos:      返回的树形集合，递归时会向其中添加子节点TreeItemVo
     *                      这个列表本身是创建一次的，但数据会随递归过程不断填充
     * @param rootResource: 当前递归的父节点
     *                      是当前递归调用中的“根节点”资源。每次递归时，rootResource代表树形结构中的一个节点，而这个节点的子节点将会在递归过程中处理。
     *                      如果是第一层递归，rootResource是整个树的根节点，后续的递归中它的子资源会被作为新的rootResource传入，直到没有子节点为止。理
     *                      解上，它是当前递归深度的父节点，在递归的每一层中不断变化。
     * @param resourceList: 所有的资源列表 List<Resource> resourceList = resourceMapper.selectList(resource); 用于查找子资源
     *                      是一个静态的资源列表，这个列表在整个递归过程中是不会改变的
     */
    private void recursionTreeItem(List<TreeItemVo> itemVos, Resource rootResource, List<Resource> resourceList) {
        // 构建每个子节点 TreeItemVo = id + label + children
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(rootResource.getResourceNo())
                .label(rootResource.getResourceName())
                .build();

        // 获取当前子节点treeItemVo下的子资源
        // 使用 stream() API 从 resourceList 中筛选出所有 parentResourceNo 等于当前 rootResource.getResourceNo() 的资源项，这些资源项就是当前节点的子资源
        List<Resource> childrenResourceList = resourceList.stream()
                .filter(n -> rootResource.getResourceNo().equals(n.getParentResourceNo())) // 使用parentResourceNo来判断子资源
                .collect(Collectors.toList());

        // 如果有子资源，递归构建子资源
        if (!childrenResourceList.isEmpty()) {
            List<TreeItemVo> listChildren = new ArrayList<>();
            childrenResourceList.forEach(resource -> {
                // 递归调用 recursionTreeItem()，构建子资源的树形结构
                recursionTreeItem(listChildren, resource, resourceList);
            });
            // 将子资源的树形结构放入当前节点的 children 属性中
            treeItemVo.setChildren(listChildren);
        }

        // 将当前节点 treeItemVo 添加到返回的树形集合 itemVos 中
        itemVos.add(treeItemVo);
    }

    /**
     * 获取资源，用于放入树形
     *
     * @return
     */
    private List<Resource> getResources() {
        // 构造查询条件
        // entity.builder().....build(); 链式构造函数
        ResourceDto dto = ResourceDto.builder()
                .dataState(SuperConstant.DATA_STATE_0) // DATA_STATE_0：0 启用
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID)) // 父资源编号 "100001000000000"
                .resourceType(SuperConstant.MENU).build(); // "资源类型：s平台 c目录 m菜单 r按钮"
        Resource resource = new Resource();
        BeanUtil.copyProperties(dto, resource);
        System.out.println("resourceTreeVo()_resource:" + resource);
        // 从数据库中查询符合条件的资源列表
        List<Resource> resourceList = resourceMapper.selectList(resource);
        System.out.println("resourceTreeVo()_resourceList:" + resourceList);
        if (EmptyUtil.isNullOrEmpty(resourceList)) {
            throw new RuntimeException("资源信息未定义");
        }
        return resourceList;
    }

    // 辅助方法：递归获取所有子孙节点
    private List<Resource> getAllDescendants(Resource resource) {
        List<Resource> descendants = new ArrayList<>();

        // 获取直接子资源
        Resource query = Resource.builder()
                .parentResourceNo(resource.getResourceNo())
                .build();
        List<Resource> children = resourceMapper.selectList(query);

        for (Resource child : children) {
            // 添加当前子资源
            descendants.add(child);

            // 递归添加孙资源
            if (!SuperConstant.BUTTON.equals(child.getResourceType())) {
                descendants.addAll(getAllDescendants(child));
            }
        }

        return descendants;
    }
}
